안드로이드(Android) - 서비스(Service) :: 안드로이드 설치 및 개발[SSISO Community]
 
SSISO 카페 SSISO Source SSISO 구직 SSISO 쇼핑몰 SSISO 맛집
추천검색어 : JUnit   Log4j   ajax   spring   struts   struts-config.xml   Synchronized   책정보   Ajax 마스터하기   우측부분

안드로이드 설치 및 개발
[1]
등록일:2018-07-15 08:31:31 (0%)
작성자:
제목:안드로이드(Android) - 서비스(Service)

서비스란?

오늘은 안드로이드 Application을 구성하는 4가지 컴포넌트 중 하나인 Service에 대해 공부해보겠습니다.

Service 무엇인가?

Service는 Activity처럼 사용자와 사용자와 상호작용하는 컴포넌트가 아니고, Background에서 동작하는 컴포넌트입니다.

Receiver도 Activity를 종료해도 계속 살아있지만, 최소 Activity 한번의 실행은 꼭 필요합니다.


Service 왜 필요한가?

Activity가 종료되어 있는 상태에서도 동작하기 위해서 만들어진 컴포넌트입니다.

음악 App 같은 경우에 노래를 틀고 음악 App을 종료해도 노래가 계속 나옵니다.

만약 Service가 실행되고 있는 상태라면 안드로이드 OS에서는 해당 Process를 죽이지 않도록 방지하고 관리합니다.

그렇게 때문에 메모리 부족이나 특별한 경우를 제외하고는 Background 동작을 수행하도록 설계되어있습니다.


Service 사용방법

Service에는 두 가지가 있습니다.

첫 번째, startService()를 이용하는 방법

두 번째, bindService()를 이용하는 방법



프로젝트 생성

My Service 라는 이름으로 안드로이드 프로젝트를 생성하겠습니다.

최소 버전은 16, 레이아웃은 Empty입니다.

Service 이용해서 시간재는 타이머를 만들어 시간이 되면 알림을 주는 앱을 만들어보겠습니다.

타이머를 Service를 이용해서 만들기 때문에 Activity를 끄더라도 계속 타이머는 진행됩니다.

따라서 원하는 시간이 되면 알림이 뜨도록 설정해놓고 다른 작업을 할 수 있습니다.



레이아웃 수정

LinearLayout으로 변경하고 tvCounter라는 이름으로 TextView를 만들어 이 곳에 숫자를 표현하겠습니다.

그리고 START 버튼과 STOP 버튼을 만들겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ktds.cocomo.myapplication.MainActivity">
 
    <TextView
        android:id="@+id/tvCounter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="70dp"
        android:text="0" />
 
    <LinearLayout
        android:orientation="vertical"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
 
        <Button
            android:id="@+id/btnStart"
            android:text="START"
            android:textSize="40dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
 
        <Button
            android:id="@+id/btnStop"
            android:text="STOP"
            android:textSize="40dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
 
    </LinearLayout>
 
</LinearLayout>
 
cs



Service 만들기

MyCounterService라는 이름으로 Service를 만듭니다.

패키지 우클릭 > new > Service > Service 를 통해 만듭니다.

Service는 Activity와 별도로 따로 계속 수행해되야 하기 때문에 Thread를 이용합니다.

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class MyCounterService extends Service {

    private boolean isStop;

    public MyCounterService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // Thread를 이용해 Counter 실행시키기
        Thread counter = new Thread(new Counter());
        counter.start();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class Counter implements Runnable {

        private int count;
        private Handler handler = new Handler();

        @Override
        public void run() {

            for (count = 0; count < 50; count++) {

                // STOP 버튼을 눌렀다면 종료한다.
                if (isStop) {
                    break;
                }


                /**
                 * Thread 안에서는 UI와 관련된 Toast를 쓸 수 없습니다.
                 * 따라서, Handler를 통해 이용할 수 있도록 만들어줍니다.
                 */
                handler.post(new Runnable() {
                    @Override
                    public void run() {

                        // Toast로 Count 띄우기
                        Toast.makeText(getApplicationContext()
                                , count + ""
                                , Toast.LENGTH_SHORT).show();

                        // Log로 Count 찍어보기
                        Log.d("COUNT", count + "");

                    }


                });

                // Sleep을 통해 1초씩 쉬도록 한다.
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "서비스가 종료되었습니다.", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    /**
     * StopService가 실행될 때 호출된다.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        isStop = true;
    }
}



MainActivity

MainActivity에서 방금 만든 MyCounterService에 대한 제어를 합니다.

START 버튼을 누르면 MyCounterService를 시작하고 STOP 버튼을 누르면 종료하도록합니다.

public class MainActivity extends AppCompatActivity {

    private TextView tvCounter;
    private Button btnStart;
    private Button btnStop;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvCounter = (TextView) findViewById(R.id.tvCounter);
        btnStart = (Button) findViewById(R.id.btnStart);
        btnStop = (Button) findViewById(R.id.btnStop);

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // START 버튼을 누르면 MyCounterService 시작
                Intent intent = new Intent(MainActivity.this, MyCounterService.class);
                startService(intent);
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // STOP 버튼을 누르면 MyCounterService 종료
                Intent intent = new Intent(MainActivity.this, MyCounterService.class);
                stopService(intent);
            }
        });
    }
}



Activity로 count 보내기

Service에서 진행되는 count 숫자를 Activity로 보여주기 위해선 AIDL 파일이 필요합니다.

IMyCounterService라는 이름으로 AIDL 파일을 만들어보겠습니다.


만들면 다음과같이 Interface라고 만들어집니다.

다음과 같이 초기화 시켜줍니다.

// Declare any non-default types here with import statements
interface IMyCounterService {
    int getCount();
}


Ctrl + F9 를 누르면 Make Project가 됩니다. 해줍시다.


MyCounterService에서 이용합니다.

Service, Activity 통신을 위한 Binder 객체Activity에게 getCount() 메소드를 제공해 Service의 count 값을 전달합니다.

/**
 * Service, Activity 통신을 위한 Binder 객체
 * Activity에게 getCount() 메소드를 제공해 Service의 count 값을 전달한다.
 */
IMyCounterService.Stub binder = new IMyCounterService.Stub() {
    @Override
    public int getCount() throws RemoteException {
        return 0;
    }
};


바인더를 Return 합니다.

@Override
public IBinder onBind(Intent intent) {
    return binder;
}


count 변수를 Service의 멤버변수로 빼서 count를 반환합니다.

private int count;

public MyCounterService() {
}

/**
 * Service, Activity 통신을 위한 Binder 객체
 * Activity에게 getCount() 메소드를 제공해 Service의 count 값을 전달한다.
 */
IMyCounterService.Stub binder = new IMyCounterService.Stub() {
    @Override
    public int getCount() throws RemoteException {
        return count;
    }
};

이로서 Service쪽의 세팅은 끝났습니다.


최종 MyCountService 코드입니다.

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.Toast;

import java.util.Locale;

public class MyCounterService extends Service {

    private boolean isStop;
    private int count;
    private TextToSpeech tts;

    public MyCounterService() {
    }

    /**
     * Service, Activity 통신을 위한 Binder 객체
     * Activity에게 getCount() 메소드를 제공해 Service의 count 값을 전달한다.
     */
    IMyCounterService.Stub binder = new IMyCounterService.Stub() {
        @Override
        public int getCount() throws RemoteException {
            return count;
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();

        tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                tts.setLanguage(Locale.KOREAN);
            }
        });

        // Thread를 이용해 Counter 실행시키기
        Thread counter = new Thread(new Counter());
        counter.start();
    }

    /**
     * StopService가 실행될 때 호출된다.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        isStop = true;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        isStop = true;
        return super.onUnbind(intent);
    }

    private class Counter implements Runnable {


        private Handler handler = new Handler();

        @Override
        public void run() {

            /**
             * 10초로 설정
             */
            for (count = 0; count < 10; count++) {

                // STOP 버튼을 눌렀다면 종료한다.
                if (isStop) {
                    break;
                }


                /**
                 * Thread 안에서는 UI와 관련된 Toast를 쓸 수 없습니다.
                 * 따라서, Handler를 통해 이용할 수 있도록 만들어줍니다.
                 */
                handler.post(new Runnable() {
                    @Override
                    public void run() {

                        // Toast로 Count 띄우기
                        Toast.makeText(getApplicationContext()
                                , count + ""
                                , Toast.LENGTH_SHORT).show();

                        // Log로 Count 찍어보기
                        Log.d("COUNT", count + "");

                    }


                });

                // Sleep을 통해 1초씩 쉬도록 한다.
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "서비스가 종료되었습니다.", Toast.LENGTH_SHORT).show();
                    tts.speak("라면이 다 익었습니다.", TextToSpeech.QUEUE_ADD, null);
                }
            });
        }
    }
}




MainActivity에서 count 받아오기

MainActivity에서 우선 IMyCounterService 멤버변수를 선언합니다.

또한 Activity가 Service를 호출합니다. 이 때, 꼭 binder필요합니다.

Service가 가지고있는 binder를 전달받는다. 즉, Service에서 구체화한 getCount() 메소드를 받았습니다.

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView tvCounter;
    private Button btnStart;
    private Button btnStop;
    private IMyCounterService binder;

    /**
     * Activity가 Service를 호출합니다.
     * 이 때, 꼭 binder가 필요합니다.
     */
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            /**
             * Service가 가지고있는 binder를 전달받는다.
             * 즉, Service에서 구체화한 getCount() 메소드를 받았습니다.
             */
            binder = IMyCounterService.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private Intent intent;
    private boolean running = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvCounter = (TextView) findViewById(R.id.tvCounter);
        btnStart = (Button) findViewById(R.id.btnStart);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, MyCounterService.class);
                bindService(intent, connection, BIND_AUTO_CREATE);
                running = true;
                new Thread(new GetCountThread()).start();
            }
        });

        btnStop = (Button) findViewById(R.id.btnStop);
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(connection);
                running = false;
            }
        });
    }

    /**
     *
     */
    private class GetCountThread implements Runnable {

        // binder에서 count가져와서 set시키려면 handler 필요
        private Handler handler = new Handler();

        @Override
        public void run() {

            while (running) {

                if(binder == null) {
                    continue;
                }

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            tvCounter.setText(binder.getCount() + "");
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                });

                // 0.5초 텀을 준다.
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}




결과

START 버튼을 눌러서 시작하겠습니다.

Service에서 1초에 1씩 올라가고있는 count 변수를 IMyCountService 통해 Activity로 받아와서 보여주고있습니다.


STOP 버튼을 누르면 서비스가 종료되었습니다. 라는 Toast가 뜹니다.


이상으로 서비스 실습 마치겠습니다 ~



[본문링크] 안드로이드(Android) - 서비스(Service)
[1]
코멘트(이글의 트랙백 주소:/cafe/tb_receive.php?no=34709
작성자
비밀번호

 

SSISOCommunity

[이전]

Copyright byCopyright ⓒ2005, SSISO Community All Rights Reserved.